package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.NestedQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.*;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepository;
import com.atguigu.tingshu.search.repository.SuggestIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Function;
import java.util.stream.Collectors;


@Slf4j
@Service
@RefreshScope
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumIndexRepository albumIndexRepository;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private SuggestIndexRepository suggestIndexRepository;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${ranking.dimension.array}")
    private String rankingDimensionArray;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void upperAlbum(Long albumId) {
        //  本质：将数据保存到es、 数据载体：AlbumInfoIndex   es
        //  1.专辑基本信息 2.专辑属性信息 3.专辑分类信息 --专辑微服务提供数据:  4.用户信息
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        //  多线程：
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //  获取专辑信息
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            //  判断
            Assert.notNull(albumInfoResult, "专辑返回结果不存在");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑不存在");
            //  赋值：
            //  处理专辑信息，属性拷贝：属性必须一致.
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);
            return albumInfo;
        }, threadPoolExecutor);

        //  获取属性标签
        CompletableFuture<Void> attributeCompletableFuture = CompletableFuture.runAsync(() -> {
            Result<List<AlbumAttributeValue>> albumAttributeValueResult = albumInfoFeignClient.findAlbumAttributeValue(albumId);
            //判断
            Assert.notNull(albumAttributeValueResult, "专辑属性返回结果不存在");
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueResult.getData();
            Assert.notNull(albumAttributeValueList, "专辑属性不存在");
            //  想不到... 循环遍历获取数据，同时返回一个新的集合。map stream 对应的泛型：就是集合的泛型.
            List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueList.stream().map(albumAttributeValue -> {
                //  创建对象 AttributeValueIndex
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                //  赋值：
                //            attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                //            attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                BeanUtils.copyProperties(albumAttributeValue, attributeValueIndex);
                //  返回
                return attributeValueIndex;
            }).collect(Collectors.toList());
            //  给属性赋值：
            albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
        }, threadPoolExecutor);

        //  包含一级分类，二级分类，三级分类; 查询base_category_view 数据
        CompletableFuture<Void> categoryCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            Result<BaseCategoryView> baseCategoryViewResult = categoryFeignClient.getCategoryView(albumInfo.getCategory3Id());
            Assert.notNull(baseCategoryViewResult, "分类返回结果不存在");
            BaseCategoryView baseCategoryView = baseCategoryViewResult.getData();
            Assert.notNull(baseCategoryView, "分类不存在");
            //  赋值分类数据
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
            albumInfoIndex.setCategory3Id(baseCategoryView.getCategory3Id());
        }, threadPoolExecutor);

        CompletableFuture<Void> userCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            //  根据用户Id 获取到用户信息
            Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfo(albumInfo.getUserId());
            Assert.notNull(userInfoResult, "用户返回结果不存在");
            UserInfo userInfo = userInfoResult.getData();
            Assert.notNull(userInfo, "用户不存在");
            //  赋值主播名称
            albumInfoIndex.setAnnouncerName(userInfo.getNickname());
        }, threadPoolExecutor);

        //  赋值：初始化统计信息
        //更新统计量与得分，默认随机，方便测试
        CompletableFuture<Void> AlbumStatCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            Result<AlbumStatVo> albumStat = albumInfoFeignClient.getAlbumStat(albumInfo.getId());
            Assert.notNull(albumStat, "专辑统计信息返回结果不存在");
            AlbumStatVo albumStatVo = albumStat.getData();
            Assert.notNull(albumStatVo, "专辑统计信息不存在");
            albumInfoIndex.setPlayStatNum(albumStatVo.getPlayStatNum());
            albumInfoIndex.setSubscribeStatNum(albumStatVo.getSubscribeStatNum());
            albumInfoIndex.setBuyStatNum(albumStatVo.getBuyStatNum());
            albumInfoIndex.setCommentStatNum(albumStatVo.getCommentStatNum());
        }, threadPoolExecutor);
        //  设置热度排名
        albumInfoIndex.setHotScore(new Random().nextDouble(10000));
        //  进行多任务组合：
        CompletableFuture.allOf(
                albumInfoCompletableFuture,
                attributeCompletableFuture,
                categoryCompletableFuture,
                userCompletableFuture,
                AlbumStatCompletableFuture).join();
        //  保存albumInfoIndex到es！ 必须先有索引库.
        //  -- 使用内置类，在启动项目的时候，会根据AlbumInfoIndex.class 中定义的数据类型与索引库名称，自动创建.
        albumIndexRepository.save(albumInfoIndex);

        //  上架添加提词数据.
//  创建对象 专辑标题提词
        SuggestIndex suggestIndex = new SuggestIndex();
        suggestIndex.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndex.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        this.suggestIndexRepository.save(suggestIndex);

//  专辑简介提词
        SuggestIndex albumIntroSuggestIndex = new SuggestIndex();
        albumIntroSuggestIndex.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        albumIntroSuggestIndex.setTitle(albumInfoIndex.getAlbumIntro());
        albumIntroSuggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        albumIntroSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumIntro())}));
        albumIntroSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumIntro())}));
        this.suggestIndexRepository.save(albumIntroSuggestIndex);

// 专辑主播提词
        SuggestIndex announcerSuggestIndex = new SuggestIndex();
        announcerSuggestIndex.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        announcerSuggestIndex.setTitle(albumInfoIndex.getAnnouncerName());
        announcerSuggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAnnouncerName()}));
        announcerSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAnnouncerName())}));
        announcerSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAnnouncerName())}));
        suggestIndexRepository.save(announcerSuggestIndex);

        //	将新增的商品SKUID存入布隆过滤器
        //	获取布隆过滤器，将新增skuID存入布隆过滤器
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);
    }


    @Override
    public void lowerAlbum(Long albumId) {
        albumIndexRepository.deleteById(albumId);
    }


    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //构建dsl语句
        SearchRequest request = this.buildQueryDsl(albumIndexQuery);
        //  调用查询方法
        SearchResponse<AlbumInfoIndex> response = null;
        try {
            response = elasticsearchClient.search(request, AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //得到返回的结果集
        AlbumSearchResponseVo responseVo = this.parseSearchResult(response);
        responseVo.setPageSize(albumIndexQuery.getPageSize());
        responseVo.setPageNo(albumIndexQuery.getPageNo());
        // 获取总页数
        long totalPages = (responseVo.getTotal() + albumIndexQuery.getPageSize() - 1) / albumIndexQuery.getPageSize();
        responseVo.setTotalPages(totalPages);
        return responseVo;
    }


    /**
     * 获取查询请求对象 - 生成 dsl 语句.
     *
     * @param albumIndexQuery
     * @return
     */
    private SearchRequest buildQueryDsl(AlbumIndexQuery albumIndexQuery) {
        //  检索入口： 关键词
        String keyword = albumIndexQuery.getKeyword();
        SearchRequest.Builder requestBuilder = new SearchRequest.Builder();
        //  {query - bool }
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
        //  {query - bool - should - match}
        //  MatchQuery.Builder matchQuery = new MatchQuery.Builder();
        //  matchQuery.field("albumTitle").query(keyword);
        //  boolQuery.should(f-> f.match(matchQuery.build()));
        if (!StringUtils.isEmpty(keyword)) {
            //  {query - bool - should - match}
            boolQuery.should(f -> f.match(s -> s.field("albumTitle").query(keyword)));
            boolQuery.should(f -> f.match(s -> s.field("albumIntro").query(keyword)));
            //  高亮
            requestBuilder.highlight(h -> h.fields("albumTitle",
                    //                    f->f.preTags("<font color:red>").postTags("</font>")
                    f -> f.preTags("<span style=color:red>").postTags("</span>")
            ));
        }

        //  入口：分类Id  复制小括号，写死右箭头，落地大括号
        //  一级分类Id
        Long category1Id = albumIndexQuery.getCategory1Id();
        if (!ObjectUtils.isEmpty(category1Id)) {
            boolQuery.filter(f -> f.term(s -> s.field("category1Id").value(category1Id)));
        }
        //  二级分类Id
        Long category2Id = albumIndexQuery.getCategory2Id();
        if (!ObjectUtils.isEmpty(category2Id)) {
            boolQuery.filter(f -> f.term(s -> s.field("category2Id").value(category2Id)));
        }
        //  三级分类Id
        Long category3Id = albumIndexQuery.getCategory3Id();
        if (!ObjectUtils.isEmpty(category3Id)) {
            boolQuery.filter(f -> f.term(s -> s.field("category3Id").value(category3Id)));
        }

        //  根据属性Id 检索 前端传递数据的时候 属性Id:属性值Id 属性Id:属性值Id
        List<String> attributeList = albumIndexQuery.getAttributeList();
        //  判断集合不为空
        if (!CollectionUtils.isEmpty(attributeList)) {
            //  循环遍历.
            for (String attribute : attributeList) {
                //  需要使用 : 分割
                String[] split = attribute.split(":");
                //  判断
                if (null != split && split.length == 2) {
                    //  创建nestedQuery 对象.
                    NestedQuery nestedQuery = NestedQuery.of(f -> f.path("attributeValueIndexList")
                            .query(q -> q.bool(
                                    m -> m.must(s -> s.match(
                                                    a -> a.field("attributeValueIndexList.attributeId").query(split[0])
                                            ))
                                            .must(s -> s.match(
                                                    a -> a.field("attributeValueIndexList.valueId").query(split[1])
                                            ))
                            ))
                    );
                    boolQuery.filter(f -> f.nested(nestedQuery));
                }
            }
        }

        //  排序 分页 高亮 排序（综合排序[1:desc] 播放量[2:desc] 发布时间[3:desc]；asc:升序 desc:降序）
        String order = albumIndexQuery.getOrder();
        //  定义一个排序字段
        String orderField = "";
        //  定义一个排序规则
        String sort = "";
        //  判断
        if (!StringUtils.isEmpty(order)) {
            //  分割数据
            String[] split = order.split(":");
            //  判断这个数组
            if (null != split && split.length == 2) {
                switch (split[0]) {
                    case "1":
                        orderField = "hotScore";
                        break;
                    case "2":
                        orderField = "playStatNum";
                        break;
                    case "3":
                        orderField = "createTime";
                        break;
                }
                sort = split[1];
            }
            //  判断 desc SortOrder.Desc  asc SortOrder.Asc
            String finalSort = sort;
            String finalOrderField = orderField;
            requestBuilder.sort(f -> f.field(o -> o.field(finalOrderField).order("asc".equals(finalSort) ? SortOrder.Asc : SortOrder.Desc)));
        } else {
            //  默认排序规则 _score
            requestBuilder.sort(f -> f.field(o -> o.field("_score").order(SortOrder.Desc)));
        }
        //  字段选择
        requestBuilder.source(s -> s.filter(f -> f.excludes("attributeValueIndexList")));
        //  分页： (pageNo-1)*pageSize()
        Integer from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        requestBuilder.from(from);
        requestBuilder.size(albumIndexQuery.getPageSize());

        //  {query }
        //  GET /albuminfo/_search
        requestBuilder.index("albuminfo").query(f -> f.bool(boolQuery.build()));
        //  创建对象
        SearchRequest searchRequest = requestBuilder.build();
        System.out.println("dsl:\t" + searchRequest.toString());
        //  返回
        return searchRequest;
    }


    /**
     * 获取结果集对象
     *
     * @param searchResponse
     * @return
     */
    private AlbumSearchResponseVo parseSearchResult(SearchResponse<AlbumInfoIndex> searchResponse) {
        //  创建对象
        AlbumSearchResponseVo searchResponseVo = new AlbumSearchResponseVo();
        //  private List<AlbumInfoIndexVo> list = new ArrayList<>();
        //  private Long total;//总记录数
        //  获取数据
        HitsMetadata<AlbumInfoIndex> hits = searchResponse.hits();
        //  总记录数
        searchResponseVo.setTotal(hits.total().value());
        //  获取数据
        List<Hit<AlbumInfoIndex>> subHist = hits.hits();
        //  判断
        if (!CollectionUtils.isEmpty(subHist)) {
            //  循环遍历.
            List<AlbumInfoIndexVo> list = subHist.stream().map(albumInfoIndexHit -> {
                //  创建对象
                AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
                AlbumInfoIndex albumInfoIndex = albumInfoIndexHit.source();
                //  进行赋值
                BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
                //  判断用户是否根据关键词进行检索.
                if (null != albumInfoIndexHit.highlight().get("albumTitle")) {
                    //  获取高亮数据
                    String albumTitle = albumInfoIndexHit.highlight().get("albumTitle").get(0);
                    //  赋值高亮数据
                    albumInfoIndexVo.setAlbumTitle(albumTitle);
                }
                //  返回数据
                return albumInfoIndexVo;
            }).collect(Collectors.toList());
            //  赋值
            searchResponseVo.setList(list);
        }
        //  返回数据
        return searchResponseVo;
    }

    @Override
    public List<Map<String, Object>> channel(Long category1Id) {
        //  map.put("baseCategory3",三级分类对象);   map.put("list",专辑集合列表);
        //  从mapkey 对应的value 入手分析实现过程!
        //  1.  通过一级分类Id获取到三级分类列表;
        Result<List<BaseCategory3>> baseCategory3ListResult = categoryFeignClient.findTopBaseCategory3(category1Id);
        //  判断：
        Assert.notNull(baseCategory3ListResult, "查询三级分类集合失败");
        //  findTopBaseCategory3 limit 7 --> 有七条数据; 1001 ... 1007
        List<BaseCategory3> baseCategory3List = baseCategory3ListResult.getData();
        Assert.notNull(baseCategory3List, "查询三级分类集合失败");
        //  通过这个集合获取到三级分类Id集合：
        List<Long> category3IdList = baseCategory3List.stream().map(BaseCategory3::getId).collect(Collectors.toList());
        //  通过三级分类Id查找三级分类对象; category3Id -> BaseCategory3;
        //  baseCategory3List-->Map(key=category3Id,BaseCategory3); Function.identity()：t -> t
        Map<Long, BaseCategory3> category3Map = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, Function.identity()));

        //  List<Long>-->List<FieldValue> FieldValue.of(BaseCategory3::getId)
        List<FieldValue> fieldValueList = baseCategory3List.stream().map(baseCategory3 -> FieldValue.of(baseCategory3.getId())).collect(Collectors.toList());
        //  专辑集合列表
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                            .query(q -> q.terms(t -> t.field("category3Id")
                                    .terms(t1 -> t1.value(fieldValueList))))
                            .aggregations("agg_category3Id", a -> a.terms(t -> t.field("category3Id"))
                                    .aggregations("topSixHotScoreAgg", a1 -> a1.topHits(t1 -> t1.size(6)
                                            .sort(s1 -> s1.field(f -> f.field("hotScore").order(SortOrder.Desc)))))
                            )
                    ,
                    AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //  获取结果组装数据;
        Aggregate aggregate = searchResponse.aggregations().get("agg_category3Id");
        List<Map<String, Object>> list = aggregate.lterms().buckets().array().stream().map(bucket -> {
            //  存储数据；需要创建一个map集合：
            HashMap<String, Object> map = new HashMap<>();
            //  先获取key;
            long category3Id = bucket.key();
            //  存储第一个数据三级分类对象： baseCategory3.name
            map.put("baseCategory3", category3Map.get(category3Id));
            //  获取专辑集合列表;
            Aggregate topSixHotScoreAgg = bucket.aggregations().get("topSixHotScoreAgg");
            List<AlbumInfoIndex> albumInfoIndexList = topSixHotScoreAgg.topHits().hits().hits().stream().map(hit -> JSON.parseObject(hit.source().toString(), AlbumInfoIndex.class)).collect(Collectors.toList());
            map.put("list", albumInfoIndexList);
            //  返回map;
            return map;
        }).collect(Collectors.toList());
        //  返回数据
        return list;
    }


    @Override
    public List<String> completeSuggest(String keyword) {
        System.out.println("Searching suggestions for keyword: " + keyword);

        // java动态生成dsl语句
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();
        searchRequestBuilder.index("suggestinfo").suggest(
                s -> s.suggesters("suggestionKeyword", f -> f.prefix(keyword).completion(
                                c -> c.field("keyword").skipDuplicates(true).size(10).fuzzy(
                                        z -> z.fuzziness("auto"))))
                        .suggesters("suggestionkeywordSequence", f -> f.prefix(keyword)
                                .completion(c -> c.field("keywordSequence").skipDuplicates(true).size(10)
                                        .fuzzy(z -> z.fuzziness("auto"))))
                        .suggesters("suggestionkeywordPinyin",
                                f -> f.prefix(keyword).completion(c -> c.field("keywordPinyin")
                                        .skipDuplicates(true).fuzzy(f1 -> f1.fuzziness("auto")).size(10)))
        );

        // 构建请求对象
        SearchRequest searchRequest = searchRequestBuilder.build();

        // 获取查询结果
        SearchResponse<SuggestIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(searchRequest, SuggestIndex.class);
            System.out.println("Search executed successfully, took: " + searchResponse.took() + "ms");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 获取到结果集,数据转换
        HashSet<String> titleSet = new HashSet<>();
        titleSet.addAll(this.parseResultData(searchResponse, "suggestionKeyword"));
        titleSet.addAll(this.parseResultData(searchResponse, "suggestionkeywordPinyin"));
        titleSet.addAll(this.parseResultData(searchResponse, "suggestionkeywordSequence"));

        // 返回数据
        return new ArrayList<>(titleSet);
    }

    private List<String> parseResultData(SearchResponse<SuggestIndex> searchResponse, String keyword) {
        //  根据key 获取options:
        List<Suggestion<SuggestIndex>> suggestionList = searchResponse.suggest().get(keyword);
        if (!CollectionUtils.isEmpty(suggestionList)) {
            for (Suggestion<SuggestIndex> suggestIndexSuggestion : suggestionList) {
                return suggestIndexSuggestion.completion().options().stream().map(option -> option.source().getTitle()).collect(Collectors.toList());
            }
        }
        //  返回数据
        return new ArrayList<>();
    }


    @Override
    public void updateLatelyAlbumRanking() {
        //获取所有一级分类数据
        Result<List<BaseCategory1>> baseCategory1Result = categoryFeignClient.findAllCategory1();
        Assert.notNull(baseCategory1Result, "获取一级分类数据结果失败");
        List<BaseCategory1> baseCategory1List = baseCategory1Result.getData();
        Assert.notNull(baseCategory1List, "获取一级分类数据失败");
        //获取排序的维度
        String[] split = rankingDimensionArray.split(",");
        //循环遍历
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            //baseCategory1.getId()
            //Hash数据结构:hset key field value; key=category1Id, field =热度/播放量/订阅量/ value=热度data/播放量data;
            // String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
            //排行榜数据从哪里来?es中!
            //  获取一级分类Id
            Long category1Id = baseCategory1.getId();
            for (String rangking : split) {
                //  调用es api
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(
                            s -> s.index("albuminfo")
                                    .query(q -> q.term(t -> t.field("category1Id").value(category1Id)))
                                    .sort(s1 -> s1.field(f -> f.field(rangking).order(SortOrder.Desc)))
                            ,
                            AlbumInfoIndex.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                //  获取集合列表;
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
                //  将每次获取的数据添加到缓存中;
                redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX + category1Id, rangking, albumInfoIndexList);
            }
        }
    }

    @Override
    public List<AlbumInfoIndexVo> findRankingList(Long category1Id, String dimension) {
        return (List<AlbumInfoIndexVo>) redisTemplate.boundHashOps(RedisConstant.RANKING_KEY_PREFIX + category1Id).get(dimension);
    }
}
